package orderProcessingProcess.client.junit;

//import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import javax.xml.ws.soap.SOAPFaultException;

import junit.framework.Assert;

import orderProcessingProcess.callbackHandlerSecurity.ClientPasswordCallbackHandler;
import orderProcessingProcess.exceptions.faults.UnknownCustomerFault;
import orderProcessingProcess.model.Address;
import orderProcessingProcess.model.Customer;
import orderProcessingProcess.model.Payment_Preference;
import orderProcessingProcess.server.BankingService;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.handler.WSHandlerConstants;
// import org.junit.BeforeClass;
import org.junit.Before;
//import org.junit.BeforeClass;
import org.junit.Test;

public class TestBankingServiceClient {

	private static final QName SERVICE_NAME = new QName(
			"http://infosys.tuwien.ac.at/ait09/ass1/dto/notification", "BankingService");
	private static final QName PORT_NAME = new QName(
			"http://infosys.tuwien.ac.at/ait09/ass1/dto/notification", "BankingPT");

	// Endpoint Address
	private static String bankingServiceAddress = "http://localhost:8084/bankingservice";
	private static BankingService bankingService;
	//private static BankingService bankingService;
	
    @Before //Class
    public void init()
    {
    	JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
    	factory.getInInterceptors().add(new LoggingInInterceptor());
    	factory.getOutInterceptors().add(new LoggingOutInterceptor());
    	factory.setServiceClass(BankingService.class);
    	factory.setAddress(bankingServiceAddress);
    	bankingService = (BankingService) factory.create();
    }
	
	@Test
	public void testBankService(){
		
		Service service = Service.create(SERVICE_NAME);
		
		// Add a port to the Service
		service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, bankingServiceAddress);

		//BankingService bankingService = service.getPort(BankingService.class);****************************************
		Client client = ClientProxy.getClient(bankingService);
		
		Endpoint cxfEndpoint = client.getEndpoint();
		cxfEndpoint.getEndpointInfo().setAddress(bankingServiceAddress);
		
		// Security part
		Map<String, Object> outProps = new HashMap<String, Object>();
		outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
		outProps.put(WSHandlerConstants.USER, "username");
		outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
		outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallbackHandler.class.getName());

		WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);

		//cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor()); // 2.0.x only; not needed in 2.1+
		cxfEndpoint.getOutInterceptors().add(wssOut);
		
		Customer c = this.createCustomer();
		
		
		try{
			//chargeCreditCard
			bankingService.chargeCreditCard(c, 123.00);
			
			// doBankTransfer
			bankingService.doBankTransfer(c, 123.123);
			Assert.assertTrue(true);
		}catch (UnknownCustomerFault e) {
			fail(e.getMessage());
		}
	}
	
	@Test
	public void testBankServiceUserNull(){
		
		Service service = Service.create(SERVICE_NAME);
		
		// Add a port to the Service
		service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, bankingServiceAddress);

		//BankingService bankingService = service.getPort(BankingService.class);****************************************
		Client client = ClientProxy.getClient(bankingService);
		
		Endpoint cxfEndpoint = client.getEndpoint();
		cxfEndpoint.getEndpointInfo().setAddress(bankingServiceAddress);
		
		// Security part
		Map<String, Object> outProps = new HashMap<String, Object>();
		outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
		outProps.put(WSHandlerConstants.USER, "username");
		outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
		outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallbackHandler.class.getName());

		WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);

		//cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor()); // 2.0.x only; not needed in 2.1+
		cxfEndpoint.getOutInterceptors().add(wssOut);
		
		Customer c = this.createCustomer();
		
		
		try{
			//chargeCreditCard
			bankingService.chargeCreditCard(c, 123.00);
			
			Assert.assertTrue(true);
			// doBankTransfer
			bankingService.doBankTransfer(null, 123.123);
			fail();
		}catch (UnknownCustomerFault e) {
			Assert.assertEquals(e.getMessage(), "Customer argument is null.", e.getMessage());
			return;
		}
		fail();
	}
	
	@Test 
	public void testBankinServiceWrongSecurityCredentals(){
		
		Service service = Service.create(SERVICE_NAME);
		
		// Add a port to the Service
		service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, bankingServiceAddress);

		//BankingService bankingService = service.getPort(BankingService.class);
		Client client = ClientProxy.getClient(bankingService);
		
		Endpoint cxfEndpoint = client.getEndpoint();
		cxfEndpoint.getEndpointInfo().setAddress(bankingServiceAddress);
		
		// Security part
		Map<String, Object> outProps = new HashMap<String, Object>();
		outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
		outProps.put(WSHandlerConstants.USER, "wrong_username");
		outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
		outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallbackHandler.class.getName());

		WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);

		//cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor()); // 2.0.x only; not needed in 2.1+
		cxfEndpoint.getOutInterceptors().add(wssOut);
		
		Customer c = this.createCustomer();
		
		//boolean testResult = false;
		//chargeCreditCard
		try
		{
			//chargeCreditCard
			bankingService.chargeCreditCard(c, 123.00);
			fail();
			// doBankTransfer
			bankingService.doBankTransfer(c, 123.123);
			//Assert.assertTrue(true);
		}
		catch (Exception e) 
		{
			Assert.assertEquals(e.getMessage(), "WRONG CREDENTIALS");
			return;
		}
		fail();
	}
	
	
	@Test
	public void testBankingServiceWithoutSecurityCredentials(){
		
		Service service = Service.create(SERVICE_NAME);
		
		// Add a port to the Service
		service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, bankingServiceAddress);

		//BankingService bankingService = service.getPort(BankingService.class);
		Client client = ClientProxy.getClient(bankingService);
		
		Endpoint cxfEndpoint = client.getEndpoint();
		cxfEndpoint.getEndpointInfo().setAddress(bankingServiceAddress);
		
		Customer c = this.createCustomer();
		
		boolean testResult = false;
		//chargeCreditCard
		try{
			bankingService.chargeCreditCard(c, 123.00);
			bankingService.doBankTransfer(c, 123.123);
			//fail();
		}catch(SOAPFaultException e){
			// Test OK
			Assert.assertEquals("An error was discovered processing the <wsse:Security> header", e.getMessage());
			testResult = true;
		}catch (UnknownCustomerFault e) {
			fail(e.getMessage());
		}
		Assert.assertTrue(testResult);
	}
	
	/*private BankingService initWithSecurity(){
		
		Service service = Service.create(SERVICE_NAME);
		
		// Add a port to the Service
		service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, bankingServiceAddress);

		BankingService bankingService = service.getPort(BankingService.class);
		Client client = ClientProxy.getClient(bankingService);
		
		Endpoint cxfEndpoint = client.getEndpoint();
		cxfEndpoint.getEndpointInfo().setAddress(bankingServiceAddress);
		
		// Security part
		Map<String, Object> outProps = new HashMap<String, Object>();
		outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
		outProps.put(WSHandlerConstants.USER, "username");
		outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
		outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallbackHandler.class.getName());

		WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);

		//cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor()); // 2.0.x only; not needed in 2.1+
		cxfEndpoint.getOutInterceptors().add(wssOut);
		return bankingService;
	}*/
	
	private Customer createCustomer() {

		Address addr1 = new Address();
		addr1.setId("001");
		addr1.setStreet("1st Avenue");
		addr1.setCity("New Your");
		addr1.setHouse(1);
		addr1.setDoor(1);
		addr1.setZip_code("10000");

		Customer customer1 = new Customer();
		customer1.setId("00001");
		customer1.setName("John Foo");
		customer1.setAddress(addr1);
		customer1.setPaymentPreference(Payment_Preference.Credit_Card);
		return customer1;
	}
}

